package com.cskaoyan.javase.oop3._2inner._6lambda._1basic;

/**
 * Lambda表达式的简化
 * 基于下列Lambda表达式的语法：
 * (形参列表) -> {
 *  // 方法体
 * }
 * Lambda表达式能够简化的前提是：
 * 它是功能接口的子类对象，而功能接口中有且只有一个必须要实现的抽象方法！
 * 当然简化,不能够使Lambda表达式存在歧义
 * 逐个语法结构进行简化:
 *      1."(形参列表)"能不能简化?
 *      形参当中的数据类型,写与不写是没有区别的
 *      所以可以去掉,可以省略掉
 *      特殊的:
 *          a.如果方法只有一个形参,那么"()"数据类型可以一起省略.
 *          b.如果方法没有形参是无参方法,这时是不能省略"()"的
 *
 *      2."{}"能不能去掉呢?
 *      当然是可以的
 *      当Lambda表达式的重写方法体中的语句仅有一条时
 *      可以去掉"{}"
 *      特殊情况:
 *      当方法体中的语句仅有一条且这条语句就是方法的返回值语句时,可以连带return + {}一起省略
 *
 *      上述简化当中,最重要的简化肯定是"{}"的简化
 *      为了让代码更加简洁优雅,去掉Lambda表达式的"{}"是必然的需求
 *      但是一条语句能够重写完毕某个功能接口中的抽象方法是很少见的场景
 *      如果重写方法体中存在很多条语句,那么如何去掉"{}"呢?
 *
 *      Java当中提供了特殊的语法来简化这种场景下的"{}"
 *      这种语法就是"方法引用 method reference"
 *
 * 方法引用(重要):
 *      Lambda表达式实质上就是实现了一个功能接口中的抽象方法
 *      这个抽象方法的实现既可以通过语法直接写在Lambda表达式
 *      还可以指向"其他的已经存在,已经实现的方法"
 *      用这些"已经存在的,已经实现的方法"作为Lambda表达式表示的子类对象中抽象方法的实现
 *      也就是说
 *          可以用方法引用这种语法,将Lambda表达式中的"{}"转嫁到另外一个独立的方法中
 *          这样Lambda表达式的"{}"就被去掉了
 *
 *      什么样的方法可以作为功能接口中抽象方法的实现呢?
 *      对于一个抽象方法来说:
 *      返回值类型 方法名(形参列表);
 *      这个已存在的,已实现的方法,要求:
 *          1.修饰符列表有没有要求?
 *              没有要求
 *              访问权限修饰符? 没有要求,但是要在用到的位置,能够访问到这个方法.
 *              static? 没有任何要求,静态与非静态完全不影响方法实现功能,只影响方法调用的方式
 *
 *          2.返回值类型有没有要求?
 *              有要求,要求兼容:
 *              a.如果是基本数据类型返回值类型和void,要求完全保持一致
 *              b.如果接口中的抽象方法返回一个父类类型,那么这个已经存在的方法,允许保持一致,也可以返回子类类型
 *
 *          3.方法名有没有要求?
 *              没有要求,随便起名字
 *
 *          4.形参列表有没有要求?
 *              必须保持一致,当然形参的名字可以变化.
 *
 *  方法引用的具体语法有两种方式:
 *          1.带"->"的形式
 *              语法:
 *              (形参列表) -> 已实现的方法的方法调用(形参列表);
 *              解释:
 *                  a.语法前后的"形参列表"必须保持一致,完全相同,都是直接照抄抽象方法的形参列表.
 *                  b."已实现的方法的方法调用"如何理解呢?
 *                      如果是一个静态方法,用类名.调用
 *                      如果是一个成员方法,用对象名.调用
 *
 *          2.(终极形式,优先考虑该形式,因为它最简洁)
 *              省略"->"的形式
 *              语法:
 *              方法的归属者::方法名;
 *              解释:
 *                  1."形参列表"和"->"全部被省略了
 *                  2.方法的归属者怎么看?
 *                      static方法属于类,就写类名
 *                      成员方法属于对象,就写匿名对象/对象名
 *
 *
 * @since 17:07
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        INoReturnTwoParam ip = (int num1, int num2) -> {
            System.out.println(num1 + num2);
        };
        ip.test(10, 10);
        //上述Lambda表达式简化为:
        INoReturnTwoParam ip2 = (num1, num2) -> {
            System.out.println(num1 + num2);
        };

        INoReturnOneParam ip3 = a -> {
            System.out.println(a);
        };
        ip3.test(666);

        // 上述Lambda表达式可以简化为:
        INoReturnOneParam ip4 = a -> System.out.println(a);

        IHasReturnNoParam ip5 = () -> {
            return 888;
        };
        // 上述Lambda表达式可以简化为:
        IHasReturnNoParam ip6 = () -> 888;
        System.out.println(ip6.test());

        INoReturnNoParam ip7 = () -> {
            System.out.println("hello world!");
            System.out.println("hello world!");
            System.out.println("hello world!");
            System.out.println("hello world!");
        };
        // 以上Lambda表达式简化成:
        INoReturnNoParam ip8 = () -> Demo.test();
        ip8.test();
        // 以上方法引用可以继续简化

        INoReturnNoParam ip9 = Demo::test;
        ip9.test();

        System.out.println("--------------------------------");

        IA ia = b -> new Demo().myTest(b);
        System.out.println(ia.test(111));
        // 以上方法引用可以继续简化
        Demo d = new Demo();
        IA ia2 = d::myTest;
        System.out.println(ia2.test(999));
    }

    public static void test() {
        System.out.println("hello world!");
        System.out.println("hello world!");
        System.out.println("hello world!");
        System.out.println("hello world!");
    }

    // 写一个已实现方法,作为功能接口IA中抽象方法test的实现
    private String myTest(int num) {
        System.out.println("我是一个大坏蛋!");
        System.out.println("你是一个好人!但是我们不合适~~");
        System.out.println("Lambda表达式~~" + num);
        return "hello world!";
    }
}

@FunctionalInterface
interface IA {
    Object test(int a);
}

//无返回值无参数的功能接口
@FunctionalInterface
interface INoReturnNoParam {
    void test();
}

//无返回值有一个参数的功能接口
@FunctionalInterface
interface INoReturnOneParam {
    void test(int a);
}

//无返回值两个参数的功能接口
@FunctionalInterface
interface INoReturnTwoParam {
    void test(int a, int b);
}

//有返回值无参数的功能接口
@FunctionalInterface
interface IHasReturnNoParam {
    int test();
}

//有返回值一个参数的功能接口
@FunctionalInterface
interface IHasReturnOneParam {
    int method(int a);
}

//有返回值两个参数的功能接口
@FunctionalInterface
interface IHasReturnTwoParam {
    int test(int a, int b);
}